#include "stdio.h"
#include "bsp_date.h"
#include "oled.h"
#include "bsp_led.h"

// store last time for better display without flicker //
struct timeStruct l_structTimeData = {
	.time = {
        .Hours = 25,
        .Minutes = 60,
        .Seconds = 60
    },
   .date = {
        .Year = 100,
        .Month = 13,
        .Date = 32,
        .WeekDay = 8
		}};

/*
		function: Time_Display
		* description: display time both in normal mode and configur mode
		* input: 
		t_structTimeData: time structure to display
		clear: whether clear the last time structure l_structTimeData
		setpos: select normal mode or set position in configure mode
			0x00: normal mode 
			0x01: setting Year
			0x02: setting Month 
			0x03: setting Date
			0x04: setting Hours
			0x05: setting Minutes
			0x06: setting Seconds
*/	
void Time_Display(struct timeStruct* t_structTimeData, uint8_t clear, uint8_t setpos)
{
	char date_str[100];
	/* clear last time stamp */
	if(clear){
		l_structTimeData.time.Hours = 25;
		l_structTimeData.time.Minutes = 60;
		l_structTimeData.time.Seconds = 60;
		l_structTimeData.date.Year = 100;
		l_structTimeData.date.Month = 13;
		l_structTimeData.date.Date = 32;
	}
	/* display date partly */
	switch(setpos){
		case 0x00: // normal mode
		default:	 // set time mode or confirm/cancel mode
			sprintf(date_str, "%d.%02d.%02d", 2000+t_structTimeData->date.Year, t_structTimeData->date.Month, t_structTimeData->date.Date);
			OLED_ShowString(date_x, date_y, (uint8_t*) date_str, sizeof(date_str));
			break;
		case 0x01: // set year mode
			sprintf(date_str, "%d.%02d.%02d", 2000+t_structTimeData->date.Year, t_structTimeData->date.Month, t_structTimeData->date.Date);
			OLED_ShowString(date_x, date_y, (uint8_t*) date_str, sizeof(date_str));
			sprintf(date_str, "    ");
			OLED_ShowString(date_x, date_y, (uint8_t*) date_str, sizeof(date_str));
			break;
		case 0x02: // set month mode
			sprintf(date_str, "%d.%02d.%02d", 2000+t_structTimeData->date.Year, t_structTimeData->date.Month, t_structTimeData->date.Date);
			OLED_ShowString(date_x, date_y, (uint8_t*) date_str, sizeof(date_str));
			sprintf(date_str+5, "  ");
			OLED_ShowString(date_x, date_y, (uint8_t*) date_str, sizeof(date_str));
		case 0x03: // set date mode
			sprintf(date_str, "%d.%02d.%02d", 2000+t_structTimeData->date.Year, t_structTimeData->date.Month, t_structTimeData->date.Date);
			OLED_ShowString(date_x, date_y, (uint8_t*) date_str, sizeof(date_str));
			sprintf(date_str+8, "  ");
			OLED_ShowString(date_x, date_y, (uint8_t*) date_str, sizeof(date_str));
	}
	/* display time partly */
	switch(setpos){
		case 0x00: // normal mode
			if(t_structTimeData->time.Hours != l_structTimeData.time.Hours){
				OLED_ShowNum(time_x, time_y, t_structTimeData->time.Hours, 2, 16);
				OLED_ShowChar(time_x + (hour_num - 1) * chr_width, time_y, ':', 16);
				OLED_ShowNum(time_x + hour_num * chr_width, time_y, t_structTimeData->time.Minutes, 2, 16);
				OLED_ShowChar(time_x + (hour_num + minute_num - 1) * chr_width, time_y, ':', 16);
				OLED_ShowNum(time_x + (hour_num + minute_num) * chr_width, time_y, t_structTimeData->time.Seconds, 2,16);
			}
			else if(t_structTimeData->time.Minutes != l_structTimeData.time.Minutes){
				OLED_ShowNum(time_x + hour_num * chr_width, time_y, t_structTimeData->time.Minutes, 2, 16);
				OLED_ShowNum(time_x + (hour_num + minute_num) * chr_width, time_y, t_structTimeData->time.Seconds, 2,16);
			}
			else if(t_structTimeData->time.Seconds != l_structTimeData.time.Seconds){
				OLED_ShowNum(time_x + (hour_num + minute_num) * chr_width, time_y, t_structTimeData->time.Seconds, 2,16);
			}
			l_structTimeData = *t_structTimeData;
			break;
		case 0x04: // set hour mode
			OLED_ShowNum(time_x, time_y, t_structTimeData->time.Hours, 2, 16);
			OLED_ShowChar(time_x + (hour_num - 1) * chr_width, time_y, ':', 16);
			OLED_ShowNum(time_x + hour_num * chr_width, time_y, t_structTimeData->time.Minutes, 2, 16);
			OLED_ShowChar(time_x + (hour_num + minute_num - 1) * chr_width, time_y, ':', 16);
			OLED_ShowNum(time_x + (hour_num + minute_num) * chr_width, time_y, t_structTimeData->time.Seconds, 2,16);
			OLED_ShowString(time_x, time_y, (uint8_t*) "  ", 16);
			break;
		case 0x05: // set minute mode
			OLED_ShowNum(time_x, time_y, t_structTimeData->time.Hours, 2, 16);
			OLED_ShowChar(time_x + (hour_num - 1) * chr_width, time_y, ':', 16);
			OLED_ShowNum(time_x + hour_num * chr_width, time_y, t_structTimeData->time.Minutes, 2, 16);
			OLED_ShowChar(time_x + (hour_num + minute_num - 1) * chr_width, time_y, ':', 16);
			OLED_ShowNum(time_x + (hour_num + minute_num) * chr_width, time_y, t_structTimeData->time.Seconds, 2,16);
			OLED_ShowString(time_x + hour_num * chr_width, time_y, (uint8_t*) "  ", 16);
			break;
		case 0x06: // set second mode
			OLED_ShowNum(time_x, time_y, t_structTimeData->time.Hours, 2, 16);
			OLED_ShowChar(time_x + (hour_num - 1) * chr_width, time_y, ':', 16);
			OLED_ShowNum(time_x + hour_num * chr_width, time_y, t_structTimeData->time.Minutes, 2, 16);
			OLED_ShowChar(time_x + (hour_num + minute_num - 1) * chr_width, time_y, ':', 16);
			OLED_ShowNum(time_x + (hour_num + minute_num) * chr_width, time_y, t_structTimeData->time.Seconds, 2,16);
			OLED_ShowString(time_x + (hour_num + minute_num) * chr_width, time_y, (uint8_t*) "  ", 16);
			break;
		default:	 // set date mode or confirm/cancel mode
			OLED_ShowNum(time_x, time_y, t_structTimeData->time.Hours, 2, 16);
			OLED_ShowChar(time_x + (hour_num - 1) * chr_width, time_y, ':', 16);
			OLED_ShowNum(time_x + hour_num * chr_width, time_y, t_structTimeData->time.Minutes, 2, 16);
			OLED_ShowChar(time_x + (hour_num + minute_num - 1) * chr_width, time_y, ':', 16);
			OLED_ShowNum(time_x + (hour_num + minute_num) * chr_width, time_y, t_structTimeData->time.Seconds, 2,16);
	}
}

/*
		function: Time_Get
		* description: get time data from RTC
		* input: 
			none
		* output:
			time structure
*/	
struct timeStruct Time_Get(void){
	RTC_TimeTypeDef t_time;
	RTC_DateTypeDef t_date;
	struct timeStruct structTimeData;
	
	HAL_StatusTypeDef Settime_status = HAL_RTC_GetTime(&hrtc, &t_time, RTC_FORMAT_BIN);
	HAL_StatusTypeDef Setdate_status = HAL_RTC_GetDate(&hrtc, &t_date, RTC_FORMAT_BIN);
	
	structTimeData.date = t_date;
	structTimeData.time = t_time;
	
	return structTimeData;
}

/*
		function: SetedDisplay
		* description: display instruction in configure mode
		* input: 
			flag: describe in which mode
				0: cancel 
				1: confirm
				2: if confirm 
				3: setting now
*/	
void SetedDisplay(uint8_t flag){
	char instruction[15] = "1:next 2:plus";
	char ifsetstr[15] = "1:yes 2:no   ";
	char setedstr[15] = "Seted!push 1  ";
	char nosetedstr[15] = "Cancel!push 1 ";
	if(flag == 1){
		OLED_ShowString(set_x, set_y, (uint8_t *) setedstr, 8);
	}
	else if(flag == 2){
		OLED_ShowString(set_x, set_y, (uint8_t *) ifsetstr, 8);
	}
	else if(flag == 3){
		OLED_ShowString(set_x, set_y, (uint8_t *) instruction, 8);
	}
	else{
		OLED_ShowString(set_x, set_y, (uint8_t *) nosetedstr, 8);
	}
}

